home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / aztecnos.arc / HAPN.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-02-13  |  10.9 KB  |  484 lines

  1. /*  Driver for HAPN-1 8273 card
  2.  *  Jon Bloom, KE3Z; adapted from KA9Q's PC-100 driver
  3.  *  Modified Rx interrupt routine to prevent lockup
  4.  *  John Tanner VK2ZXQ 6th Feb 1988
  5.  *  Adapted back into 871225.9 by KA9Q 15 Feb 1988
  6.  */
  7. #include <stdio.h>
  8. #include "global.h"
  9. #include "timer.h"
  10. #include "mbuf.h"
  11. #include "iface.h"
  12. #include "hapn.h"
  13. #include "ax25.h"
  14. #include "trace.h"
  15.  
  16. extern struct iface *Ifaces;
  17. extern struct mbuf *Hopper;
  18. int hapn_init(), hapn_stop(), ax_send(), ax_output(),hapn_raw();
  19. void (*getirq())();    /* Getirq is a function returning a pointer to
  20.              * a function returning void */
  21. static void htxint(),hrxint();
  22.  
  23. struct hapn Hapn[NHAPN];
  24. void ha0vec();
  25. void (*H_handle[])() = { ha0vec };
  26. int16 Nhapn;
  27.  
  28. /*  send command to the 8273
  29.  *  "base" = base port of 8273
  30.  *  "cmd"  = command byte
  31.  *  "np"   = number of parameter bytes
  32.  *  "p1"   = first parameter (parameters are int)
  33.  */
  34. /*VARARGS3*/
  35. static
  36. cmd_8273(base, cmd, np, p1)
  37. int16 base;
  38. int cmd, np, p1;
  39. {
  40.     int *p;
  41.  
  42.     while(inportb(base+STA) & CBSY)
  43.         ;
  44.     outportb(base+CMD, cmd);
  45.     p = &p1;
  46.     while(np--){
  47.         while(inportb(base+STA) & CPBF)
  48.             ;
  49.         outportb(base+PAR, *p++);
  50.     }
  51. }
  52.  
  53. /*  Start receiver of 8273 */
  54. static
  55. hrxgo(hp)
  56. register struct hapn *hp;
  57. {
  58.     cmd_8273(hp->base, GENERAL_RX, 2, hp->bufsiz & 0xff, hp->bufsiz >> 8);
  59. }
  60.  
  61. /*  Interrupt service function.  Entered with hapn index
  62.  *  The "flag" variable is used in this routine to indicate a
  63.  *  valid TX or RX interrupt. If an invalid interrupt is detected
  64.  *  the 8273 is reset.
  65.  */
  66. void
  67. haint(dev)
  68. int dev;
  69. {
  70.     register struct hapn *hp;
  71.     register int16 base;
  72.     char flag = 0;
  73.  
  74.     hp = &Hapn[dev];
  75.     base = hp->base;
  76.  
  77.     /*  Check for TX interrupt  */
  78.     if(inportb(base+STA) & TXINT){
  79.         flag = 1;    /* Valid interrupt, set flag */
  80.         htxint(hp);
  81.     }
  82.     /*  Check for RX interrupt  */
  83.     if(inportb(base+STA) & RXINT){
  84.         flag = 1;    /* Valid interrupt, set flag */
  85.         hrxint(hp);
  86.     }
  87.     /* Check for unknown interrupt  */
  88.     if(!flag){
  89.         hp->badint++;    /* Increment error counter */
  90.         hapn_init(hp);    /* Reinitialise the 8273 */
  91.     }
  92. }
  93. /*  RX interrupt service
  94.  *  if status register bit "RXIRA" is set, interrupt is final,
  95.  *  otherwise, interrupt is data request
  96.  */
  97. static void
  98. hrxint(hp)
  99. register struct hapn *hp;
  100. {
  101.     register struct mbuf *bp;
  102.     register int16 base;
  103.     unsigned char results[10];
  104.     struct phdr *phdr;
  105.  
  106.     hp->rxints++;
  107.     base = hp->base;
  108.  
  109.     if(inportb(base+STA) & RXIRA){
  110.         /* RX result interrupt
  111.          * If the result is a good frame 3 bytes need to be read
  112.          * If an error has occurred only one byte need to be read
  113.          */
  114.  
  115.         /* Read first result byte and test for good data */
  116.         if((results[0]=(inportb(base + RXI))) == 0xe0){
  117.             /* Good result; read two more result bytes */
  118.             while((inportb(base + STA) & RXIRA) == 0)
  119.                 ;
  120.             /* Read second result byte */
  121.             results[1] = inportb(base + RXI);
  122.             /* Wait for third result byte  */
  123.             while((inportb(base + STA) & RXIRA) == 0)
  124.                 ;  
  125.             results[2] = inportb(base + RXI);/* Read it */
  126.  
  127.             /* Since this frame is ok put it on the queue */
  128.             bp = alloc_mbuf(sizeof(struct phdr));
  129.             bp->cnt = sizeof(struct phdr);
  130.             phdr = (struct phdr *)bp->data;
  131.             phdr->iface = hp->iface;
  132.             phdr->type = TYPE_AX25;
  133.             bp->next = hp->rcvbuf;
  134.             hp->rcvbuf = NULLBUF;
  135.             enqueue(&Hopper, bp);
  136.             psignal(&Hopper,1);
  137.             hp->rframes++;
  138.         } else {
  139.             /* Error termination
  140.              * Parse RIC and act accordingly
  141.              * Only one result byte returned on error
  142.              */
  143.             switch(results[0]){
  144.             case CRCERR:
  145.                 hp->crcerr++;
  146.                 break;
  147.             case ABORT_DET:
  148.                 hp->aborts++;
  149.                 break;
  150.             case DMA_OVRN:
  151.                 hp->dmaorun++;
  152.                 break;
  153.             case MEM_OVFL:
  154.                 hp->toobig++;
  155.                 break;
  156.             case CD_LOSS:
  157.                 hp->cdloss++;
  158.                 hapn_init(hp);    /* 8273 reset on cd error */
  159.                 break;
  160.             case RX_ORUN:
  161.                 hp->rxorun++;
  162.                 break;
  163.             }
  164.             /* Throw rx buffer contents away to start over */
  165.             hp->rcp = hp->rcvbuf->data;
  166.             hp->rcvbuf->cnt = 0;
  167.         }
  168.         /* Restart the receiver */
  169.         cmd_8273(base,RX_DISABLE,0);
  170.         hrxgo(hp);
  171.     } else {
  172.         /* RX data interrupt; allocate new rx buffer if none present */
  173.         if((bp = hp->rcvbuf) == NULLBUF){
  174.             bp = hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  175.             if(bp == NULLBUF){
  176.                 /* No memory available */
  177.                 hp->nomem++;
  178.                 cmd_8273(base, RX_DISABLE, 0);
  179.                 hrxgo(hp);
  180.                 return;
  181.             }
  182.             /* Init buffer pointer */
  183.             hp->rcp = hp->rcvbuf->data;
  184.         }
  185.         /*  Barf if rx data is more than buffer can hold (should never
  186.          *  happen since 8273 is also counting bytes).
  187.          */
  188.         if(bp->cnt++ >= hp->bufsiz){
  189.             hp->toobig++;
  190.             cmd_8273(base, RX_DISABLE, 0);
  191.             hrxgo(hp);
  192.             free_p(bp);
  193.             hp->rcvbuf = NULLBUF;
  194.             return;
  195.         }
  196.         /* Store the received byte */
  197.         *hp->rcp++ = inportb(base+RXD);
  198.     }
  199. }
  200.  
  201. /*  test for busy channel (CD active)
  202.  *  returns TRUE if channel busy
  203.  */
  204. static int
  205. hcdchk(base)
  206. int16 base;
  207. {
  208.     char isav;
  209.  
  210.     isav = dirps();
  211.     cmd_8273(base, READ_A, 0);
  212.     while(!(inportb(base+STA) & CRBF))
  213.         ;
  214.     restore(isav);
  215.     return((inportb(base+RES) & CD) != 0);
  216. }
  217.  
  218. /*  TX interrupt service
  219.  *  if status register bit "TXIRA" is set, interrupt is final,
  220.  *  otherwise, interrupt is data request
  221.  */
  222. static void
  223. htxint(hp)
  224. register struct hapn *hp;
  225. {
  226.     char isav;
  227.     register int16 base;
  228.     int16 len;
  229.     char c;
  230.  
  231.     isav = dirps();
  232.     hp->txints++;
  233.     base = hp->base;
  234.  
  235.     c = 0;
  236.     if(inportb(base+STA) & TXIRA){        /* TX result interupt */
  237.         hp->tstate = IDLE;
  238.         free_p(hp->sndbuf);
  239.         hp->sndbuf = NULLBUF;
  240.  
  241.         /*  Read result  */
  242.         while((inportb(base+STA) & (TXINT | TXIRA)) != (TXINT | TXIRA))
  243.             ;
  244.         c = inportb(base+TXI);
  245.  
  246.         /*  Test for tx abort  */
  247.         switch(c & 0x1f){
  248.         case DMA_URUN:
  249.             hp->t_urun++;
  250.             break;
  251.         case CTS_LOSS:
  252.             hp->ctsloss++;
  253.             break;
  254.         case ABORT_CMPLT:
  255.             hp->taborts++;
  256.             break;
  257.         }
  258.     }
  259.     switch(hp->tstate){
  260.     case IDLE:    /*  See if a buffer is ready to be sent  */
  261.         if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF)
  262.             break;
  263.  
  264.     case DEFER:    /*  Busy-channel check  */
  265.         if(hp->mode == CSMA && (c & 0x1f) != EARLY_TXI){
  266.             if(hcdchk(base)){
  267.                 hp->tstate = DEFER;
  268.                 start_timer(&hp->defer);
  269.                 break;
  270.             }
  271.         }
  272.         /*  Start transmitter  */
  273.         stop_timer(&hp->defer);
  274.         len = len_mbuf(hp->sndbuf);
  275.         cmd_8273(base, TX_FRAME, 2, len & 0xff, len >> 8);
  276.         hp->tstate = ACTIVE;
  277.         hp->tframes++;
  278.         break;
  279.     case ACTIVE:    /*  Get next byte to send  */
  280.         if(pullup(&hp->sndbuf, &c, 1) != 1){
  281.             cmd_8273(base, ABORT_TXF, 0);
  282.             hp->tstate = IDLE;
  283.         } else
  284.             outportb(base+TXD, c);
  285.         break;
  286.     }
  287.     restore(isav);
  288. }
  289.  
  290. /*  Attach a HAPN adaptor to the system
  291.  *  argv[0]:  hardware type, must be "hapn"
  292.  *  argv[1]:  I/O address, e.g. "0x310"
  293.  *  argv[2]:  vector, e.g. "2"
  294.  *  argv[3]:  mode, must be "ax25"
  295.  *  argv[4]:  interface name, e.g. "ha0"
  296.  *  argv[5]:  rx packet buffer size in bytes
  297.  *  argv[6]:  maximum transmission unit in bytes
  298.  *  argv[7]:  channel-access mechanism, "csma" or "full"
  299.  */
  300. int
  301. hapn_attach(argc, argv)
  302. int argc;
  303. char *argv[];
  304. {
  305.     register struct iface *if_h;
  306.     struct hapn *hp;
  307.     int dev, i;
  308.     char isav;
  309.     static struct {
  310.         char *str;
  311.         char type;
  312.     } ch_access [] = { "csma", 0, "full", 1 };
  313.  
  314.     if(Nhapn >= NHAPN){
  315.         printf("Too many HAPN adaptors\n");
  316.         return -1;
  317.     }
  318.     if(if_lookup(argv[4]) != NULLIF){
  319.         printf("Interface %s already exists\n",argv[4]);
  320.         return -1;
  321.     }
  322.     dev = Nhapn++;
  323.     hp = &Hapn[dev];
  324.  
  325.     /*  Initialize hardware constants */
  326.     hp->base = htoi(argv[1]);
  327.     hp->vec = htoi(argv[2]);
  328.  
  329.     /*  Save original interrupt vector  */
  330.     hp->oldvec = getirq(Hapn[dev].vec);
  331.  
  332.     /*  Set new interrupt vector  */
  333.     setirq(hp->vec, H_handle[dev]);
  334.  
  335.     /*  Create new interface structure  */
  336.     if_h = (struct iface *) calloc(1,sizeof(struct iface));
  337.     hp->iface = if_h;
  338.  
  339.     /*  Fill interface structure  */
  340.     if_h->name = strdup(argv[4]);
  341.     if_h->mtu = atoi(argv[6]);
  342.     if_h->dev = dev;
  343.     if_h->stop = hapn_stop;
  344.     if_h->output = ax_output;
  345.     if_h->raw = hapn_raw;
  346.  
  347.     if(strcmp(argv[3], "ax25")){
  348.         printf("Mode %s unknown for interface %s\n", argv[3], argv[4]);
  349.         free(if_h->name);
  350.         free((char *) if_h);
  351.         return -1;
  352.     }
  353.     axarp();
  354.     if(Mycall.call[0] == '\0'){
  355.         printf("set mycall first\n");
  356.         free(if_h->name);
  357.         free((char *) if_h);
  358.         return -1;
  359.     }
  360.     if_h->send = ax_send;
  361.     if(if_h->hwaddr == NULLCHAR)
  362.         if_h->hwaddr = malloc(sizeof(Mycall));
  363.     memcpy(if_h->hwaddr,(char *)&Mycall,sizeof(Mycall));
  364.     /*  Link the interface into the interface list  */
  365.     if_h->next = Ifaces;
  366.     Ifaces = if_h;
  367.  
  368.     /*  Fill the local data structure  */
  369.     hp->bufsiz = atoi(argv[5]);
  370.     for(i = 0; i < (sizeof ch_access / sizeof ch_access[0]); i++)
  371.         if(!strcmp(argv[7], ch_access[i].str))
  372.             hp->mode = ch_access[i].type;
  373.  
  374.     /*  Initialize the hardware  */
  375.     isav = dirps();
  376.     hapn_init(hp);
  377.  
  378.     /* Initialize the defer timer */
  379.     hp->defer.start = 1;
  380.     hp->defer.func = htxint;
  381.     hp->defer.arg = (char *)hp;
  382.  
  383.     /*  Enable the interrupt  */
  384.     maskon(hp->vec);
  385.  
  386.     restore(isav);
  387.     return 0;
  388. }
  389.  
  390. /*  initialize the HAPN adaptor */
  391. int
  392. hapn_init(hp)
  393. register struct hapn *hp;
  394. {
  395.     register int16 base;
  396.     char isav;
  397.  
  398.     isav = dirps();
  399.     base = hp->base;
  400.  
  401.     /*  Reset the 8273 */
  402.     outportb(base+RST, 1);
  403.     outportb(base+RST, 0);
  404.     inportb(base+TXI);        /* Clear any old IR contents */
  405.     inportb(base+RXI);
  406.  
  407.     /*  Select the operating modes  */
  408.     cmd_8273(base, SET_XFER, 1, 1);
  409.     cmd_8273(base, SET_MODE, 1, HDLC | EARLY | PREFRM | FLG_STM);
  410.     cmd_8273(base, SET_SERIAL, 1, NRZI);
  411.     cmd_8273(base, SET_B, 1, IRQ_ENB | RTS);
  412.     cmd_8273(base, RST_B, 1, 0xff ^ RTS);
  413.     hrxgo(hp);
  414.     restore(isav);
  415.     return 0;
  416. }
  417.  
  418. /*  shut down the HAPN adaptor */
  419. int
  420. hapn_stop(iface)
  421. struct iface *iface;
  422. {
  423.     int16 dev;
  424.     int16 base;
  425.     struct hapn *hp;
  426.  
  427.     dev = iface->dev;
  428.     hp = &Hapn[dev];
  429.     base = hp->base;
  430.  
  431.     /*  Mask off interrupt input  */
  432.     maskoff(hp->vec);
  433.  
  434.     /*  Restore original interrupt vector  */
  435.     setirq(hp->vec,hp->oldvec);
  436.  
  437.     /*  Reset the 8273  */
  438.     outportb(base+RST, 1);
  439.     outportb(base+RST, 0);
  440.     return 0;
  441. }
  442.  
  443. /* Display adaptor statistics */
  444. int
  445. dohapnstat()
  446. {
  447.     struct hapn *hp;
  448.     int i;
  449.  
  450.     if(Nhapn == 0){
  451.         printf("No HAPN adaptor attached\n");
  452.         return 1;
  453.     }
  454.     for(i = 0; i < Nhapn; i++){
  455.         hp = &Hapn[i];
  456.         printf("HAPN %d:   rxints: %ld   txints: %ld   badint: %-5d\r\n", i,
  457.          hp->rxints,hp->txints,hp->badint);
  458.         printf(" receive  - frames:  %-5d  crcerrs: %-5d  aborts: %-5d  dmaorun: %-5d\r\n",
  459.          hp->rframes,hp->crcerr, hp->aborts, hp->dmaorun);
  460.         printf("          - toobig:  %-5d  dcdloss: %-5d  rxorun: %-5d\r\n",
  461.          hp->toobig,hp->cdloss,hp->rxorun);
  462.         printf(" transmit - frames:  %-5d  aborts : %-5d  uruns : %-5d  ctsloss: %-5d\r\n",
  463.          hp->tframes,hp->taborts, hp->t_urun, hp->ctsloss);
  464.     }
  465.     return 0;
  466. }
  467.  
  468. /* Send raw packet on HAPN interface */
  469. int
  470. hapn_raw(iface,bp)
  471. struct iface *iface;
  472. struct mbuf *bp;
  473. {
  474.     struct hapn *hp;
  475.  
  476.     hp = &Hapn[iface->dev];
  477.     enqueue(&hp->sndq, bp);
  478.  
  479.     /*  See if anything being transmitted  */
  480.     if(hp->tstate == IDLE)
  481.         htxint(hp);
  482.     return 0;
  483. }
  484.